package com.atguigu.srb.core.service.impl;

import com.atguigu.srb.base.result.ResponseEnum;
import com.atguigu.srb.base.util.JwtUtils;
import com.atguigu.srb.base.util.SrbAssert;
import com.atguigu.srb.core.pojo.entity.BorrowInfo;
import com.atguigu.srb.core.mapper.BorrowInfoMapper;
import com.atguigu.srb.core.pojo.entity.Borrower;
import com.atguigu.srb.core.pojo.entity.Lend;
import com.atguigu.srb.core.pojo.entity.UserInfo;
import com.atguigu.srb.core.pojo.vo.BorrowInfoDetailVO;
import com.atguigu.srb.core.pojo.vo.BorrowInfoVO;
import com.atguigu.srb.core.pojo.vo.BorrowerVO;
import com.atguigu.srb.core.pojo.vo.BorrowinfoSearchVO;
import com.atguigu.srb.core.service.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 借款信息表 服务实现类
 * </p>
 *
 * @author muzhao
 * @since 2024-08-19
 */
@Service
public class BorrowInfoServiceImpl extends ServiceImpl<BorrowInfoMapper, BorrowInfo> implements BorrowInfoService {
    @Resource
    UserInfoService userInfoService;
    @Resource
    LendService lendService;
    @Resource
    IntegralGradeService integralGradeService;
    @Resource
    DictService dictService;
    @Resource
    BorrowerService borrowerService;

    @Override
    public void saveApply(BorrowInfo borrowInfo, String token) {
        UserInfo userInfo = userInfoService.checkUserStatus(token);
        Long userId = userInfo.getId();
        //3、校验用户是否有待审核/还款中的借款
        //3.1 borrow_info表中 若当前用户有状体为待审核的贷款信息 不能再次借贷
        int count = this.count(Wrappers.lambdaQuery(BorrowInfo.class)
                .eq(BorrowInfo::getUserId, userId)
                .eq(BorrowInfo::getStatus, 1));
        SrbAssert.assertNotTrue(count != 0, ResponseEnum.USER_BORROW_INFO_EXISTS_ERROR);
        //3.2 lend表中 若当前用户有状态为 "待发布" 或者 "募资中" 或者 "还款中" 的标的 不能再次借贷
        /*
            CHECK(0, "待发布"),
            INVEST_RUN(1, "募资中"),
            PAY_RUN(2, "还款中"),
            PAY_OK(3, "已结清"),
            FINISH(4, "结标"),
            CANCEL(-1, "已撤标"),
         */
        count = lendService.count(Wrappers.lambdaQuery(Lend.class)
                .eq(Lend::getUserId, userId)
                .in(Lend::getStatus, 0, 1, 2));
        SrbAssert.assertNotTrue(count != 0, ResponseEnum.USER_BORROW_INFO_EXISTS_ERROR);

        //4、验证用户借款金额是否超过自己的借款额度
        BigDecimal amount = integralGradeService.getBorrowAmountByUserId(token);
        SrbAssert.assertNotTrue(borrowInfo.getAmount().doubleValue() > amount.doubleValue(), ResponseEnum.USER_AMOUNT_LESS_ERROR);

        //保存借款申请到数据库中
        borrowInfo.setUserId(userId);
        //年化利率前端提交的时 *100后的结果
        borrowInfo.setStatus(1);//审核中
        this.save(borrowInfo);

    }

    @Override
    public void getMyBorrows(Page<BorrowInfo> page, String token) {
        Long userId = JwtUtils.getUserId(token);
        //查询数据
        this.page(page, Wrappers.lambdaQuery(BorrowInfo.class)
                .eq(BorrowInfo::getUserId, userId)
                .orderByDesc(BorrowInfo::getCreateTime));
        //完善数据 将每个BorrowInfo的数据字典的name值设置到params集合中
        List<BorrowInfo> records = page.getRecords();//借款列表
        records.forEach(record -> {
            Integer status = record.getStatus();
            Integer moneyUse = record.getMoneyUse();
            Integer returnMethod = record.getReturnMethod();
            HashMap<String, String> map = new HashMap<>();
            String statusStr = getStatusStr(status);
            map.put("status", statusStr);
            map.put("moneyUse", dictService.getDictNameByDictCodeAndValue("moneyUse", moneyUse));
            map.put("returnMethod", dictService.getDictNameByDictCodeAndValue("returnMethod", returnMethod));
            record.setParams(map);
        });
    }

    private static String getStatusStr(Integer status) {
        String statusStr;
        //"状态（0：未提交，1：审核中， 2：审核通过， -1：审核不通过，-2：已撤销申请）"
        switch (status) {
            case 0:
                statusStr = "未提交";
                break;
            case 1:
                statusStr = "审核中";
                break;
            case 2:
                statusStr = "审核通过";
                break;
            case -2:
                statusStr = "已撤销申请";
                break;
            default:
                statusStr = "审核不通过";
                break;
        }
        return statusStr;
    }

    //自定义sql实现带条件分页查询借款记录
    @Override
    public Page<BorrowInfoVO> getBorrowInfoVOs2(BorrowinfoSearchVO borrowinfoSearchVO, Integer pageNum, Integer pageSize) {
        //page携带分页条件：若启用了mp的分页拦截器 page对象会被分页拦截器自动解析生成limit语句
        Page<BorrowInfoVO> page = new Page<>(pageNum, pageSize);
        //条件分页查询借款列表
        //queryWrapper携带查询条件
        QueryWrapper<BorrowInfo> wrapper = new QueryWrapper<>();
        //封装查询条件
        String keyword = borrowinfoSearchVO.getKeyword();
        if (StringUtils.isNotEmpty(keyword)) {
            wrapper.and(r -> r.like("t2.name", keyword).or().like("t2.mobile", keyword));
        }
        //1.2 借款记录状态
        Integer status = borrowinfoSearchVO.getStatus();
        if (status != null) {
            wrapper.eq("t1.status", status);
        }
        //1.3 资金用途
        Integer moneyUse = borrowinfoSearchVO.getMoneyUse();
        if (moneyUse != null) {
            wrapper.eq("t1.money_use", moneyUse);
        }
        //1.4 还款方式
        Integer returnMethod = borrowinfoSearchVO.getReturnMethod();
        if (returnMethod != null) {
            wrapper.eq("t1.return_method", returnMethod);
        }
        //1.5 借款金额区间
        BigDecimal amountStart = borrowinfoSearchVO.getAmountStart();
        BigDecimal amountEnd = borrowinfoSearchVO.getAmountEnd();
        if (amountStart != null) {
            wrapper.ge("t1.amount", amountStart);
        }
        if (amountEnd != null) {
            wrapper.le("t1.amount", amountEnd);
        }
        //1.6 申请时间范围
        String createTimeStart = borrowinfoSearchVO.getCreateTimeStart();
        String createTimeEnd = borrowinfoSearchVO.getCreateTimeEnd();
        //时间日期的比较
        if (createTimeStart!= null) {
            wrapper.ge("DATE(t1.create_time)", createTimeStart);
        }
        if (createTimeEnd!= null) {
            wrapper.le("DATE(t1.create_time)", createTimeEnd);
        }
        //1.7 还款期数的范围
        Integer periodStart = borrowinfoSearchVO.getPeriodStart();
        Integer periodEnd = borrowinfoSearchVO.getPeriodEnd();
        if (periodStart!= null) {
            wrapper.ge("t1.period", periodStart);
        }
        if (periodEnd!= null) {
            wrapper.le("t1.period", periodEnd);
        }
        //排序
        wrapper.orderByDesc("t1.create_time");
        List<BorrowInfoVO> borrowInfoVOs = baseMapper.selectBorrowInfoVOs(page,wrapper);
        borrowInfoVOs.forEach( borrowInfoVO -> {
            transferBorrowInfoVO(borrowInfoVO);
        });
        //将查询到的分页数据列表 设置到分页对象中
        page.setRecords(borrowInfoVOs);
        return page;
    }

    private void transferBorrowInfoVO(BorrowInfoVO borrowInfoVO) {
        borrowInfoVO.setPeriod(borrowInfoVO.getPeriod() + "个月");
        borrowInfoVO.setReturnMethod(dictService.getDictNameByDictCodeAndValue("returnMethod", Integer.parseInt(borrowInfoVO.getReturnMethod())));
        borrowInfoVO.setMoneyUse(dictService.getDictNameByDictCodeAndValue("moneyUse", Integer.parseInt(borrowInfoVO.getMoneyUse())));
        borrowInfoVO.setBorrowYearRate(borrowInfoVO.getBorrowYearRate() + "%");
        borrowInfoVO.setStatus(getStatusStr(Integer.parseInt(borrowInfoVO.getStatus())));
    }

    @Override
    public BorrowInfoDetailVO getBorrowInfoDetail(Long id) {
        BorrowInfoDetailVO borrowInfoDetailVO = new BorrowInfoDetailVO();
        //查询借款详情
        BorrowInfoVO borrowInfoVO = baseMapper.selectBorrowInfoDetailById(id);
        transferBorrowInfoVO(borrowInfoVO);
        borrowInfoDetailVO.setBorrowInfoVO(borrowInfoVO);
        //查询借款人信息
        Long userId = borrowInfoVO.getUserId(); //userInfo
        Borrower borrower = borrowerService.getOne(Wrappers.lambdaQuery(Borrower.class)
                .eq(Borrower::getUserId, userId)
                .select(Borrower::getId));//只查询Borrower的id
        BorrowerVO borrowerVO = borrowerService.queryBorrowerVOById(borrower.getId());
        borrowInfoDetailVO.setBorrowerVO(borrowerVO);
        return borrowInfoDetailVO;
    }

    @Override
    public Page<BorrowInfoVO> getBorrowInfoVOs(BorrowinfoSearchVO borrowinfoSearchVO, Integer pageNum, Integer pageSize) {
        //条件分页查询借款列表
        LambdaQueryWrapper<BorrowInfo> wrapper = Wrappers.lambdaQuery(BorrowInfo.class);
        //封装查询条件
        //1.1 模糊查询的关键词
//        String keyword = borrowinfoSearchVO.getKeyword();
//        //由于用户姓名和手机号存在userInfo表中 需要根据这些条件筛选数据 必须多表联查
//        if (StringUtils.isNotEmpty(keyword)){
//            wrapper.like()
//        }

        //1.2 借款记录状态
        Integer status = borrowinfoSearchVO.getStatus();
        if (status != null) {
            wrapper.eq(BorrowInfo::getStatus, status);
        }
        //1.3 资金用途
        Integer moneyUse = borrowinfoSearchVO.getMoneyUse();
        if (moneyUse != null) {
            wrapper.eq(BorrowInfo::getMoneyUse, moneyUse);
        }
        //1.4 还款方式
        Integer returnMethod = borrowinfoSearchVO.getReturnMethod();
        if (returnMethod != null) {
            wrapper.eq(BorrowInfo::getReturnMethod, returnMethod);
        }
        //1.5 借款金额区间
        BigDecimal amountStart = borrowinfoSearchVO.getAmountStart();
        BigDecimal amountEnd = borrowinfoSearchVO.getAmountEnd();
        if (amountStart != null) {
            wrapper.ge(BorrowInfo::getAmount, amountStart);
        }
        if (amountEnd != null) {
            wrapper.le(BorrowInfo::getAmount, amountEnd);
        }
        //1.6 申请时间范围
        String createTimeStart = borrowinfoSearchVO.getCreateTimeStart();
        String createTimeEnd = borrowinfoSearchVO.getCreateTimeEnd();
        //时间日期的比较
        if (createTimeStart!= null) {
            wrapper.ge(BorrowInfo::getCreateTime, createTimeStart);
        }
        if (createTimeEnd!= null) {
            wrapper.le(BorrowInfo::getCreateTime, createTimeEnd);
        }
        //1.7 还款期数的范围
        Integer periodStart = borrowinfoSearchVO.getPeriodStart();
        Integer periodEnd = borrowinfoSearchVO.getPeriodEnd();
        if (periodStart!= null) {
            wrapper.ge(BorrowInfo::getPeriod, periodStart);
        }
        if (periodEnd!= null) {
            wrapper.le(BorrowInfo::getPeriod, periodEnd);
        }

        wrapper.orderByDesc(BorrowInfo::getCreateTime);
        Page<BorrowInfo> borrowInfoPage = this.page(new Page<BorrowInfo>(pageNum, pageSize), wrapper);
        //将borrowInfoPage转为BorrowInfoVO的分页对象
        Page<BorrowInfoVO> page = new Page<>();
        //拷贝 页码 每页几条记录 总记录条数 等属性值  records属性 两个page对象的泛型不一致 导致拷贝失败
        BeanUtils.copyProperties(borrowInfoPage, page);
        List<BorrowInfoVO> vos = borrowInfoPage.getRecords().stream().map(borrowInfo -> {
            BorrowInfoVO borrowInfoVO = new BorrowInfoVO();
            borrowInfoVO.setId(borrowInfo.getId());
            borrowInfoVO.setAmount(borrowInfo.getAmount());
            borrowInfoVO.setCreateTime(borrowInfo.getCreateTime());
            borrowInfoVO.setPeriod(borrowInfo.getPeriod() + "个月");
            borrowInfoVO.setReturnMethod(dictService.getDictNameByDictCodeAndValue("returnMethod", borrowInfo.getReturnMethod()));
            borrowInfoVO.setMoneyUse(dictService.getDictNameByDictCodeAndValue("moneyUse", borrowInfo.getMoneyUse()));
            borrowInfoVO.setBorrowYearRate(borrowInfo.getBorrowYearRate() + "%");
            borrowInfoVO.setStatus(getStatusStr(borrowInfo.getStatus()));
            //根据userId查询会员信息
            UserInfo userInfo = userInfoService.getById(borrowInfo.getUserId());
            borrowInfoVO.setMobile(userInfo.getMobile());
            borrowInfoVO.setName(userInfo.getName());
            return borrowInfoVO;
        }).collect(Collectors.toList());

        page.setRecords(vos);

        return page;
    }


}
